import { 
  BoxGeometry,
  Mesh,
  MeshLambertMaterial,
  MeshStandardMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  WebGLRenderer
} from "three";
import stats from '../../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GUI } from 'dat.gui';
import { CSS3DObject, CSS3DRenderer, CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer';

let scene = new Scene();
let renderer = setRenderer();
let camera = setCamera();

const controls = {
  normalScaleX: 1,
  normalScaleY: 1,
  rotationSpeed: 0.01
}

let light = setLight();
let css3dRenderer = new CSS3DRenderer();

init();
addGUI();

const trackballControls = new OrbitControls(camera, renderer.domElement);
// 调整场景位置
trackballControls.target.set(0, 3, 0);

function render() {
  stats.update();
  trackballControls.update();

  requestAnimationFrame(render);
  renderer.render(scene, camera);
  css3dRenderer.render(scene, camera);
}
render();

function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);
  scene.add( camera );

  return camera;
}

// 灯光设置
function setLight() {
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.set(-10, 30, 40);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.decay =2;
  spotLight.penumbra = 0.05;
  spotLight.castShadow = true;

  scene.add(spotLight);

  return spotLight;
}

/** 功能区 */
function init() {
  // 添加平面
  let planeGeom = new PlaneGeometry(60, 40, 1, 1);
  let planeMate = new MeshLambertMaterial({
    color: 0xffffff,
  });
  const plane = new Mesh(planeGeom, planeMate);
  plane.receiveShadow = true;
  plane.rotation.x = -Math.PI / 2;
  scene.add(plane);

  const sphereGeom = new SphereGeometry(5, 20, 20);
  const sphereMate = new MeshStandardMaterial({ color: 0xeeee00 });
  const sphere = new Mesh(sphereGeom, sphereMate);
  sphere.position.set(0, 5, 0);
  scene.add(sphere);

  // 
  create3DLabel('Hello World').position.set(0, 3, 0);
  createSprite3DLabel('Hello Sprite').position.set(-10, 3, -5);

  css3dRenderer.setSize(window.innerWidth, window.innerHeight);
  css3dRenderer.domElement.style.position = 'absolute';
  css3dRenderer.domElement.style.top = '0px';
  css3dRenderer.domElement.style.pointerEvents = 'none';
  document.body.appendChild(css3dRenderer.domElement);
}


function addGUI(): void {
  const gui = new GUI();  

  gui.add(light, 'intensity', 0, 1).name('光照亮度');
}

function create3DLabel (label: string) {
  let div = document.createElement('div');
  div.innerText = label;
  div.classList.add('test-label');
  div.style.border = '2px solid #09f';
  div.style.color = '#ffffff';
  div.style.padding = '1px 5px';
  
  // 添加点击事件
  div.addEventListener('click', () => {
    alert('Clicked!')
  })

  let box = new Mesh(
    new BoxGeometry(1, 1, 1),
    new MeshStandardMaterial({
      visible: false,
    })
  );
  scene.add(box);

  // 转换3d元素
  let label3D = new CSS3DObject(div);
  box.add(label3D);
  box.scale.set(0.1, 0.1, 0.1);

  return box;
}

function createSprite3DLabel (label: string) {
  let div = document.createElement('div');
  div.innerText = label;
  div.classList.add('test-label');
  div.style.border = '2px solid #09f';
  div.style.color = '#ffffff';
  div.style.padding = '1px 5px';
  
  // 添加点击事件
  div.addEventListener('click', () => {
    alert('Clicked!')
  })

  let box = new Mesh(
    new BoxGeometry(1, 1, 1),
    new MeshStandardMaterial({
      visible: false,
    })
  );
  box.castShadow = true;
  scene.add(box);

  // 转换3d粒子元素
  let label3D = new CSS3DSprite(div);
  label3D.scale.set(0.1, 0.1, 0.1);
  box.add(label3D);

  return box;
}